package com.exigen.performance.test.webapp.dto;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;

import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRXlsAbstractExporterParameter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.ooxml.JRDocxExporter;

import org.primefaces.event.DateSelectEvent;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;

import com.exigen.performance.test.webapp.domain.ReportEntity;
import com.exigen.performance.test.webapp.domain.RequestTemplateEntity;
import com.exigen.performance.test.webapp.services.ReportServices;

public class RequestTemplateDto {

	private Integer rowNumber = null;

	private List<RequestTemplateEntity> requestTemplates;

	private RequestTemplateEntity selectedRequestTemplates;

	// Time interval;
	private Date fromDate;
	private Date untilDate = new Date();

	private List<String> reportType;
	private List<String> reportFormat;

	private String selectedReportType;
	private String selectedReportFormat;

	// Field to store generated report for upload;
	private StreamedContent report;

	private ReportServices reportServices;

	public RequestTemplateDto() {
		Calendar c = Calendar.getInstance();
		c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
		fromDate = c.getTime();
		reportFormat = new ArrayList<String>();
		reportFormat.add("PDF");
		reportFormat.add("XLS");
		reportFormat.add("DOCX");
		reportType = new ArrayList<String>();
		reportType.add("90%");
		reportType.add("Average");

	}

	/**
	 * Method to collect all available templates.
	 */
	public void getAllRequestTemplates() {
		if (rowNumber == null) {
			try {
				String confValue = reportServices
						.getConfiguration("ROW_NUMBER");
				rowNumber = Integer.parseInt(confValue);
			} catch (Exception e) {
				rowNumber = 20;
			}
		}
		requestTemplates = reportServices.getAllRequestTemplates();
	}

	/**
	 * Method to delete selected template.
	 */
	public void deleteTemplate() {
		if (selectedRequestTemplates != null) {
			try {
				reportServices.deleteTemplate(selectedRequestTemplates);
			} catch (Exception e) {
				FacesContext.getCurrentInstance().addMessage(
						null,
						new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error!",
								e.getMessage()));
			}
		}
	}

	/**
	 * Method that generates report using selected template.
	 */
	public void generateReport() {
		if (selectedRequestTemplates != null) {
			int reportType = -1;
			boolean validType = false;
			// Report type & format validation
			boolean validFormat = false;
			if (selectedReportType.equals("90%")) {
				reportType = 0;
				validType = true;
			}
			if (selectedReportType.equals("Average")) {
				reportType = 1;
				validType = true;
			}
			if (selectedReportFormat.equals("PDF")
					|| selectedReportFormat.equals("DOCX")
					|| selectedReportFormat.equals("XLS"))
				validFormat = true;
			if (validType && validFormat) {
				ReportEntity entity = new ReportEntity();
				entity.setIntermediate(false);
				entity.setType(reportType);
				entity.setTestSummaries(selectedRequestTemplates
						.getTestSummaries());
				entity.setTransactions(selectedRequestTemplates
						.getTransactions());
				entity.setTemplate(true);
				entity.setStartDate(fromDate);
				entity.setEndDate(untilDate);
				JasperPrint jasperPrint;
				try {
					// Passes report for report fill;
					jasperPrint = reportServices.generateReport(entity);
					// Converts filled report in correct(currently pdf only)
					// format
					// for future download;
					if (selectedReportFormat.equals("PDF")) {
						JRPdfExporter exporter = new JRPdfExporter();
						exporter.setParameter(JRExporterParameter.JASPER_PRINT,
								jasperPrint);
						ByteArrayOutputStream baos = new ByteArrayOutputStream();
						exporter.setParameter(
								JRExporterParameter.OUTPUT_STREAM, baos);
						exporter.exportReport();

						// Converting OutputStream to InputStream;
						InputStream bais = new ByteArrayInputStream(
								((ByteArrayOutputStream) baos).toByteArray());

						report = new DefaultStreamedContent(bais,
								"application/pdf",
								selectedRequestTemplates.getTemplateName()
										+ "-report.pdf");
					}
					if (selectedReportFormat.equals("XLS")) {
						JRXlsExporter exporter = new JRXlsExporter();
						exporter.setParameter(
								JRXlsAbstractExporterParameter.JASPER_PRINT,
								jasperPrint);
						ByteArrayOutputStream baos = new ByteArrayOutputStream();
						exporter.setParameter(
								JRXlsAbstractExporterParameter.OUTPUT_STREAM,
								baos);
						exporter.setParameter(
								JRXlsAbstractExporterParameter.IS_DETECT_CELL_TYPE,
								true);
						exporter.setParameter(
								JRXlsAbstractExporterParameter.IS_ONE_PAGE_PER_SHEET,
								false);
						exporter.setParameter(
								JRXlsAbstractExporterParameter.IS_WHITE_PAGE_BACKGROUND,
								true);
						exporter.setParameter(
								JRXlsAbstractExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,
								true);

						exporter.exportReport();

						// Converting OutputStream to InputStream;
						InputStream bais = new ByteArrayInputStream(
								((ByteArrayOutputStream) baos).toByteArray());

						report = new DefaultStreamedContent(bais, "text/xls",
								selectedRequestTemplates.getTemplateName()
										+ "-report.xls");
					}
					if (selectedReportFormat.equals("DOCX")) {
						JRDocxExporter exporter = new JRDocxExporter();
						exporter.setParameter(JRExporterParameter.JASPER_PRINT,
								jasperPrint);
						ByteArrayOutputStream baos = new ByteArrayOutputStream();
						exporter.setParameter(
								JRExporterParameter.OUTPUT_STREAM, baos);
						exporter.exportReport();

						// Converting OutputStream to InputStream;
						InputStream bais = new ByteArrayInputStream(
								((ByteArrayOutputStream) baos).toByteArray());

						report = new DefaultStreamedContent(bais, "text/docx",
								selectedRequestTemplates.getTemplateName()
										+ "-report.docx");

					}
				} catch (Exception e) {
					// Something went wrong during report generation
					FacesContext.getCurrentInstance().addMessage(
							null,
							new FacesMessage(FacesMessage.SEVERITY_ERROR,
									"Error!", e.getMessage()));
				}
			} else {
				// Format or report type not selected
				FacesContext.getCurrentInstance().addMessage(
						null,
						new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error!",
								"Report type not selected!"));
			}
		} else {
			// Template not selected
			FacesContext.getCurrentInstance().addMessage(
					null,
					new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error!",
							"No template selected!"));
		}

	}

	/**
	 * Saves selected from date and checks if it is smaller than until date;
	 * 
	 * @param event
	 */
	public void selectFromDate(DateSelectEvent event) {
		fromDate = event.getDate();
		if (untilDate != null) {
			if (fromDate.after(untilDate)) {
				fromDate = null;
				FacesContext.getCurrentInstance().addMessage(
						null,
						new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error!",
								"Beginning date bigger that end date!"));
			}
		}
	}

	/**
	 * Saves selected until date and check if it is bigger than from date;
	 * 
	 * @param event
	 */
	public void selectUntilDate(DateSelectEvent event) {
		untilDate = event.getDate();
		if (fromDate != null) {
			if (fromDate.after(untilDate)) {
				untilDate = null;
				FacesContext.getCurrentInstance().addMessage(
						null,
						new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error!",
								"Beginning date bigger that end date!"));
			}
		}
	}

	// Getters&Setters
	public List<RequestTemplateEntity> getRequestTemplates() {
		return requestTemplates;
	}

	public void setRequestTemplates(List<RequestTemplateEntity> requestTemplates) {
		this.requestTemplates = requestTemplates;
	}

	public RequestTemplateEntity getSelectedRequestTemplates() {
		return selectedRequestTemplates;
	}

	public void setSelectedRequestTemplates(
			RequestTemplateEntity selectedRequestTemplates) {
		this.selectedRequestTemplates = selectedRequestTemplates;
	}

	public ReportServices getReportServices() {
		return reportServices;
	}

	public void setReportServices(ReportServices reportServices) {
		this.reportServices = reportServices;
	}

	public Date getFromDate() {
		return fromDate;
	}

	public void setFromDate(Date fromDate) {
		this.fromDate = fromDate;
	}

	public Date getUntilDate() {
		return untilDate;
	}

	public void setUntilDate(Date untilDate) {
		this.untilDate = untilDate;
	}

	public List<String> getReportType() {
		return reportType;
	}

	public void setReportType(List<String> reportType) {
		this.reportType = reportType;
	}

	public List<String> getReportFormat() {
		return reportFormat;
	}

	public void setReportFormat(List<String> reportFormat) {
		this.reportFormat = reportFormat;
	}

	public String getSelectedReportType() {
		return selectedReportType;
	}

	public void setSelectedReportType(String selectedReportType) {
		this.selectedReportType = selectedReportType;
	}

	public String getSelectedReportFormat() {
		return selectedReportFormat;
	}

	public void setSelectedReportFormat(String selectedReportFormat) {
		this.selectedReportFormat = selectedReportFormat;
	}

	public StreamedContent getReport() {
		return report;
	}

	public void setReport(StreamedContent report) {
		this.report = report;
	}

	public Integer getRowNumber() {
		return rowNumber;
	}

	public void setRowNumber(Integer rowNumber) {
		this.rowNumber = rowNumber;
	}

}
